﻿using System;
using System.Collections.ObjectModel;
using System.Windows.Threading;
using StockModel;
using Utils;
using Utils.Extensions;

namespace StockAnalyst2.StockGrid
{
	internal class GridRowManager : MessageProcessor
	{
		#region Attributes

		private readonly object _rowsLock;
		private readonly ObservableCollection<RowVM> _realRows;
		private readonly Dispatcher _dispatcher;

		#endregion 

		#region Properties

		public bool IsPlaceHolderVisible { get; set; }
		public string NameFilter { get; set; }

		#endregion

		#region Public Methods

		public GridRowManager(object rowsLock, ObservableCollection<RowVM> realRows, Dispatcher dispatcher) : base("Grid Row Manager Message Processor")
		{
			_rowsLock = rowsLock;
			_realRows = realRows;
			_dispatcher = dispatcher;
		}

		public void AddRowVM(string groupName, string stockName, string stockSymbol, QuotationDailyInfo dailyInfo)
		{
			base.Messages.Add(new AddRowMessage(groupName, stockName, stockSymbol, dailyInfo));
		}

		public void RemoveRowVM(RowVM row)
		{
			base.Messages.Add(new DeleteRowMessage(row));
		}

		public void Sort()
		{
			base.Messages.Add(new Message(RowManagerMessageType.Sort));
		}

		public void RefreshRowsVisibility()
		{
			base.Messages.Add(new Message(RowManagerMessageType.RefreshVisibility));
		}

		protected override void ProcessMessage()
		{
			if (base.CurrentMessage.Type == RowManagerMessageType.AddRow)
			{
				AddRowMessage addOrder = (AddRowMessage)base.CurrentMessage;
				this.InternalAddRowVM(addOrder.GroupName, addOrder.StockName, addOrder.StockSymbol, addOrder.DailyInfo);
			}
			else if (base.CurrentMessage.Type == RowManagerMessageType.DeleteRow)
			{
				DeleteRowMessage deleteOrder = (DeleteRowMessage)base.CurrentMessage;
				this.InternalRemoveRowVM(deleteOrder.Row);
			}
			else if (base.CurrentMessage.Type == RowManagerMessageType.Sort)
			{
				this.InternalSort();
			}
			else if (base.CurrentMessage.Type == RowManagerMessageType.RefreshVisibility)
			{
				lock (_rowsLock)
				{
					foreach (RowVM row in _realRows)
					{
						this.SetRowVisibility(row);
					}
				}
			}
		}

		#endregion

		#region Private Methods

		private void InternalAddRowVM(string groupName, string stockName, string stockSymbol, QuotationDailyInfo dailyInfo)
		{
			if (_dispatcher.CheckAccess())
			{
				RowVM rowVM = new RowVM(groupName, stockName, stockSymbol, dailyInfo);
				this.SetRowVisibility(rowVM);

				lock (_rowsLock)
				{
					_realRows.Add(rowVM);
				}
			}
			else
			{
				// As the quotations are loaded just after the creation of the Row it must be created synchronously to avoid loading quotations before attaching to the quotation changed event handler
				_dispatcher.Invoke(new Action<string, string, string, QuotationDailyInfo>(this.InternalAddRowVM), new object[] { groupName, stockName, stockSymbol, dailyInfo });
			}
		}

		private void InternalSort()
		{
			if (_dispatcher.CheckAccess())
			{
				lock (_rowsLock)
				{
					_realRows.Sort(r => r.Group.Value + r.Name.Value);
				}
			}
			else
			{
				_dispatcher.Invoke(new Action(this.InternalSort));
			}
		}

		private void InternalRemoveRowVM(RowVM row)
		{
			if (_dispatcher.CheckAccess())
			{
				lock (_rowsLock)
				{
					_realRows.Remove(row);
					row.Dispose();
				}
			}
			else
			{
				_dispatcher.Invoke(new Action<RowVM>(this.InternalRemoveRowVM), new object[] { row });
			}
		}

		private void SetRowVisibility(RowVM row)
		{
			row.IsVisible = !this.IsPlaceHolderVisible && (string.IsNullOrEmpty(this.NameFilter) || row.Name.Value.Contains(this.NameFilter));
		}

		#endregion
	}
}
